#include "panel_device.h"
#include <bluetoothapis.h>
#include <vector>
#include <thread>

#define ID_BTN_USB_LINK (ID_START_PANEL_DEVICE + 0)
#define ID_BTN_BT_SCAN  (ID_START_PANEL_DEVICE + 1)
#define ID_TIM_USB_DELAY (ID_START_PANEL_DEVICE + 2)

// wxBEGIN_EVENT_TABLE(BluetoothScannerFrame, wxFrame)
//     EVT_BUTTON(wxID_ANY, BluetoothScannerFrame::OnFindBT)
// wxEND_EVENT_TABLE()

wxBEGIN_EVENT_TABLE(PanelDevice, wxPanel)
    MY_EVT_MAINFRAME_ARRIVAL(wxID_ANY, OnUSBDeviceArrival)
    MY_EVT_MAINFRAME_REMOVED(wxID_ANY, OnUSBDeviceRemove)
    EVT_BUTTON(ID_BTN_BT_SCAN, PanelDevice::OnFindBT)
    EVT_BUTTON(ID_BTN_USB_LINK, PanelDevice::OnConnectUSB)
    EVT_WINDOW_DESTROY(PanelDevice::OnDestroy)
    EVT_TIMER(ID_TIM_USB_DELAY, PanelDevice::OnTimerUSBDelay)
wxEND_EVENT_TABLE()

PanelDevice::PanelDevice(const wxString &title, wxWindowID id, wxWindow *parent)
    : wxPanel(parent,id,wxDefaultPosition,wxDefaultSize,wxTAB_TRAVERSAL)
{
    SetSize(300, 300);

    tim_usb_delay = new wxTimer(this, ID_TIM_USB_DELAY);
    btn_find_bt  = new wxButton(this,ID_BTN_BT_SCAN,wxT("Scan"));
    // btn_usb_link = new wxButton(this, ID_BTN_USB_LINK, wxT("Connect"));

    list_device = new wxListCtrl(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT);
    list_device->InsertColumn(0, wxT("Device Name"));
    list_device->InsertColumn(1, wxT("Address"));

    // text_usb_vid                 = new wxTextCtrl(this, wxID_ANY, wxT("8085"), wxDefaultPosition, wxSize(100, -1),  wxTE_PROCESS_ENTER);
    // text_usb_pid                 = new wxTextCtrl(this, wxID_ANY, wxT("0012"), wxDefaultPosition, wxSize(100, -1),  wxTE_PROCESS_ENTER);
    // text_usb_interface_num       = new wxTextCtrl(this, wxID_ANY, wxT("3"), wxDefaultPosition, wxSize(100, -1),  wxTE_PROCESS_ENTER);
    // text_usb_in_ep               = new wxTextCtrl(this, wxID_ANY, wxT("4"), wxDefaultPosition, wxSize(100, -1),  wxTE_PROCESS_ENTER);
    // text_usb_out_ep              = new wxTextCtrl(this, wxID_ANY, wxT("5"), wxDefaultPosition, wxSize(100, -1),  wxTE_PROCESS_ENTER);
    // text_usb_pid_label           = new wxStaticText(this, wxID_ANY, wxT("PID:"));
    // text_usb_vid_label           = new wxStaticText(this, wxID_ANY, wxT("VID:"));
    // text_usb_interface_num_label = new wxStaticText(this, wxID_ANY, wxT("Interface:"));
    // text_usb_in_ep_label         = new wxStaticText(this, wxID_ANY, wxT("In:"));
    // text_usb_out_ep_label        = new wxStaticText(this, wxID_ANY, wxT("Out:"));

    group_bt = new wxStaticBoxSizer(wxVERTICAL, this, wxT("Bluetooth"));
    group_bt->Add(btn_find_bt, 0, wxALIGN_CENTER_HORIZONTAL | wxALL, 5);
    group_bt->Add(list_device, 1, wxEXPAND | wxALL, 5);

    // layout_usb = new wxBoxSizer(wxHORIZONTAL);
    // layout_usb->Add(text_usb_vid_label          , 0, wxALIGN_CENTER_VERTICAL | wxALL, 0);
    // layout_usb->Add(text_usb_vid                , 0, wxALIGN_CENTER_VERTICAL | wxALL, 0);
    // layout_usb->Add(text_usb_pid_label          , 0, wxALIGN_CENTER_VERTICAL | wxALL, 0);
    // layout_usb->Add(text_usb_pid                , 0, wxALIGN_CENTER_VERTICAL | wxALL, 0);
    // layout_usb->Add(text_usb_interface_num_label, 0, wxALIGN_CENTER_VERTICAL | wxALL, 0);
    // layout_usb->Add(text_usb_interface_num      , 0, wxALIGN_CENTER_VERTICAL | wxALL, 0);
    // layout_usb->Add(text_usb_in_ep_label        , 0, wxALIGN_CENTER_VERTICAL | wxALL, 0);
    // layout_usb->Add(text_usb_in_ep              , 0, wxALIGN_CENTER_VERTICAL | wxALL, 0);
    // layout_usb->Add(text_usb_out_ep_label       , 0, wxALIGN_CENTER_VERTICAL | wxALL, 0);
    // layout_usb->Add(text_usb_out_ep             , 0, wxALIGN_CENTER_VERTICAL | wxALL, 0);
    // layout_usb->Add(btn_usb_link                , 0, wxALIGN_CENTER_VERTICAL | wxALL, 0);
    // group_usb = new wxStaticBoxSizer(wxVERTICAL, this, wxT("USB"));
    // group_usb->Add(layout_usb, 1, wxEXPAND | wxALL, 5);

    layout_main = new wxBoxSizer(wxVERTICAL);
    // layout_main->Add(group_usb, 0, wxEXPAND | wxALL, 5);
    layout_main->Add(group_bt, 1, wxEXPAND | wxALL, 5);
    SetSizer(layout_main);

    panel_info.Caption(title);
    panel_info.Dock();
    panel_info.Dockable(true);
    panel_info.CloseButton(true);
    panel_info.MaximizeButton(true);
    panel_info.MinimizeButton(true);
    panel_info.DestroyOnClose(false);
    // panel_info.Direction(wxRight);

    usb_device_vid = 0x8085;
    usb_device_pid = 0x0012;
    usb_device_in_ep  = 0x84;
    usb_device_out_ep = 0x05;
    usb_device_interface_num = 3;
    usb_comm = new USBCommunication(usb_device_vid, usb_device_pid, usb_device_interface_num);
    cmd_proc = new CommandProcess(usb_comm, usb_device_interface_num, usb_device_in_ep, usb_device_out_ep);
    tim_usb_delay->Start(100,true);
}

PanelDevice::~PanelDevice()
{
    // usb_comm->Disconnect();
    // delete layout_main;
    // delete layout_usb;
    // delete list_device;
    // delete btn_find_bt;
    // delete text_usb_vid;
    // delete text_usb_pid;
    // delete text_usb_vid_label;
    // delete text_usb_pid_label;
    // delete group_bt;
    // delete group_usb;
    // delete btn_usb_link;
    delete tim_usb_delay;
    delete cmd_proc;
    delete usb_comm;
}

void PanelDevice::OnDestroy(wxWindowDestroyEvent& event)
{
    usb_comm->Disconnect();
    event.Skip();
}


wxAuiPaneInfo &PanelDevice::GetPaneInfo()
{
    return panel_info;
}


void PanelDevice::SetShow(bool show)
{
    Show(show);
}


void PanelDevice::OnFindBT(wxCommandEvent& event)
{
    // 创建一个新的线程来执行蓝牙扫描操作
    std::thread scanThread(&PanelDevice::ScanBluetoothDevices, this);
    scanThread.detach(); // 分离线程，使得主线程不需要等待扫描线程完成
    // ScanBluetoothDevices();
}

void PanelDevice::ScanBluetoothDevices(void)
{
    wxLogInfo("Start scanning");
    btn_find_bt->Enable(false);
    // 清空列表
    list_device->DeleteAllItems();

    // 初始化 Winsock
    wxLogInfo("init Winsock");
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
        wxLogError("Failed to initialize Winsock");
        return;
    }

    // 扫描蓝牙设备
    wxLogInfo("Open Bluetooth Radio");
    HANDLE hRadio;
    BLUETOOTH_FIND_RADIO_PARAMS btfrp = { sizeof(BLUETOOTH_FIND_RADIO_PARAMS) };
    HBLUETOOTH_RADIO_FIND hFind = BluetoothFindFirstRadio(&btfrp, &hRadio);
    if (hFind != NULL)
    {
        BLUETOOTH_DEVICE_SEARCH_PARAMS btsp = { sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS) };
        btsp.fReturnAuthenticated = TRUE;
        btsp.fReturnRemembered = TRUE;
        btsp.fReturnUnknown = TRUE;
        btsp.fReturnConnected = TRUE;
        btsp.fIssueInquiry = TRUE;
        btsp.cTimeoutMultiplier = 4;
        btsp.hRadio = hRadio;

        wxLogInfo("Find first device");
        BLUETOOTH_DEVICE_INFO btdi = { sizeof(BLUETOOTH_DEVICE_INFO) };
        HBLUETOOTH_DEVICE_FIND hFindDevice = BluetoothFindFirstDevice(&btsp, &btdi);
        if (hFindDevice != NULL)
        {
            do {
                wxString name(btdi.szName, wxConvUTF8);
                wxString address = wxString::Format(wxT("%02X:%02X:%02X:%02X:%02X:%02X"),
                                                    btdi.Address.rgBytes[5], btdi.Address.rgBytes[4],
                                                    btdi.Address.rgBytes[3], btdi.Address.rgBytes[2],
                                                    btdi.Address.rgBytes[1], btdi.Address.rgBytes[0]);
                std::cout << "Name: " << name << ",Address: " << address << std::endl;
                int index = list_device->GetItemCount();
                list_device->InsertItem(index, name);
                list_device->SetItem(index, 1, address);
            } while (BluetoothFindNextDevice(hFindDevice, &btdi));
            BluetoothFindDeviceClose(hFindDevice);
        }
        else
        {
            wxLogInfo("Open Bluetooth device failed!!!");
        }
        BluetoothFindRadioClose(hFind);
    }
    else
    {
        wxLogInfo("connot find bluetooth radio");
    }

    // 清理 Winsock
    WSACleanup();
    wxLogInfo("Scan finished");
    btn_find_bt->Enable(true);

    // wxDECLARE_EVENT_TABLE();
}

void PanelDevice::OnConnectUSB(wxCommandEvent& event)
{
    // wxLogInfo("OnConnectUSB");
    event.Skip();
}

void PanelDevice::OnUSBDeviceArrival(MyEventMainFrame& event)
{
    int vid = event.GetUSB_VID();
    int pid = event.GetUSB_PID();
    wxString serialNum = event.GetUSB_SerialNumber();
    USBDeviceArrival(vid, pid, serialNum);
    event.Skip();
}

void PanelDevice::OnUSBDeviceRemove(MyEventMainFrame& event)
{
    int vid = event.GetUSB_VID();
    int pid = event.GetUSB_PID();
    wxString serialNum = event.GetUSB_SerialNumber();
    USBDeviceRemove(vid, pid, serialNum);
    event.Skip();
}

void PanelDevice::USBDeviceArrival(unsigned int vid, unsigned int pid,wxString serialNum)
{
    wxLogInfo("OnUSBDeviceArrival");
    if(pid == usb_device_pid && vid == usb_device_vid)
    {
        tim_usb_delay->Start(300,true);
    }
}

void PanelDevice::USBDeviceRemove(unsigned int vid, unsigned int pid,wxString serialNum)
{
    wxLogInfo("USBDeviceRemoval");
    if(pid == usb_device_pid && vid == usb_device_vid)
    {
        tim_usb_delay->Stop();
        usb_comm->Disconnect();
    }
}

void PanelDevice::OnTimerUSBDelay(wxTimerEvent& event)
{
    usb_comm->SetVidPid(usb_device_vid, usb_device_pid);
    usb_comm->SetInterfaceNumber(usb_device_interface_num);
    bool rc = usb_comm->Connect();
    if(rc)
    {
        CommandProcess::t_dev_info info;
        if(cmd_proc->get_device_info(info) == CommandProcess::SUCCESS)
        {
            wxLogInfo("Get device info success");
            wxLogInfo(wxString::Format("hw ver:%d",info.hw_ver ));
            wxLogInfo(wxString::Format("fw major:%d",info.fw_ver_major ));
            wxLogInfo(wxString::Format("fw minor:%d",info.fw_ver_minor ));
            wxLogInfo(wxString::Format("name:%s",info.name ));
        }
    }
    else
    {

    }
    // event.Skip();
}

int PanelDevice::WriteData(const char * data, int size)
{
    if (usb_comm->IsConnected())
    {
        if(usb_comm->WriteData(data, size,usb_device_out_ep,200) == USBCommunication::SUCCESS)
        {
            return SUCCESS;
        }
        else
        {
            return FAIL;
        }
    }
    else
    {
        return FAIL;
    }
}

int PanelDevice::ReadData(char * data, int size)
{
    if (usb_comm->IsConnected())
    {
        if(usb_comm->ReadData(data, size,usb_device_in_ep,200) == USBCommunication::SUCCESS)
        {
            return SUCCESS;
        }
        else
        {
            return FAIL;
        }
    }
    else
    {
        return FAIL;
    }
}